package com.lion.seaman.server.controller;

import com.lion.seaman.common.Constants;
import com.lion.seaman.common.model.Message;
import com.lion.seaman.common.tools.StringTools;
import com.lion.seaman.common.tools.TimeTools;
import com.lion.seaman.orm.RunSQL;
import com.lion.seaman.orm.bin.SystemConfig;
import com.lion.seaman.server.drivers.JobDriver;
import org.apache.log4j.Logger;
import org.quartz.JobDataMap;
import org.quartz.SchedulerException;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.math.BigInteger;
import java.net.URLDecoder;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.lion.seaman.server.drivers.JobDriverManager.JOB;

@Controller
@RequestMapping("/job")
public class JobManagerController extends BaseController {
    private Logger log = Logger.getLogger(JobManagerController.class);
    @Resource
    private SystemConfig systemConfig;
    @Resource
    private RunSQL runSQL;

    @ResponseBody
    @RequestMapping(value = "/get", method = RequestMethod.GET)
    public Message get(String name, @RequestParam(required = false) String group) throws IOException, ClassNotFoundException {
        if (StringTools.isBlank(group)) {
            group = Constants.DEFAULT_JOB_GROUP;
        }
        String qrtzTablePrefix = systemConfig.getProperty("org.quartz.jobStore.tablePrefix", "QRTZ_");
        String querySql = "select tr.TRIGGER_NAME,tr.TRIGGER_GROUP,de.JOB_NAME,de.JOB_GROUP,cron.CRON_EXPRESSION,tr.NEXT_FIRE_TIME,tr.PREV_FIRE_TIME,tr.TRIGGER_STATE,tr.START_TIME,de.DESCRIPTION,de.JOB_DATA from {0}TRIGGERS tr INNER JOIN {0}JOB_DETAILS de " +
                " on (tr.JOB_GROUP=de.JOB_GROUP and tr.JOB_NAME=de.JOB_NAME) " +
                "LEFT JOIN {0}CRON_TRIGGERS cron on (tr.TRIGGER_NAME=cron.TRIGGER_NAME and tr.TRIGGER_GROUP=cron.TRIGGER_GROUP) where de.JOB_NAME=''{1}'' and de.JOB_GROUP=''{2}'';";
        List<Map<String, Object>> data = runSQL.executeMap(StringTools.format(querySql, qrtzTablePrefix, name, group));
        disposeMap(data);
        Map<String, Object> result = new HashMap<>();
        if (!data.isEmpty()) {
            result = data.get(0);
        }
        return Message.success("OK", result);
    }

    @ResponseBody
    @RequestMapping(value = "/list", method = RequestMethod.GET)
    public Message list(@RequestParam int page, @RequestParam int rows) throws IOException, ClassNotFoundException {
        String qrtzTablePrefix = systemConfig.getProperty("org.quartz.jobStore.tablePrefix", "QRTZ_");
        String querySql = "select tr.TRIGGER_NAME,tr.TRIGGER_GROUP,de.JOB_NAME,de.JOB_GROUP,cron.CRON_EXPRESSION,tr.NEXT_FIRE_TIME,tr.PREV_FIRE_TIME,tr.TRIGGER_STATE,tr.START_TIME,de.DESCRIPTION,de.JOB_DATA from {0}TRIGGERS tr INNER JOIN {0}JOB_DETAILS de " +
                " on (tr.JOB_GROUP=de.JOB_GROUP and tr.JOB_NAME=de.JOB_NAME) " +
                "LEFT JOIN {0}CRON_TRIGGERS cron on (tr.TRIGGER_NAME=cron.TRIGGER_NAME and tr.TRIGGER_GROUP=cron.TRIGGER_GROUP) order by tr.START_TIME desc {1};";
        String countSql = "select count(1) from {0}JOB_DETAILS";

        if (page <= 0) {
            page = 1;
        }
        if (rows <= 0 || rows > 200) {
            rows = 10;
        }

        int index = (page - 1) * rows;
        String limit = StringTools.format(" limit {0},{1}", index + "", rows);

        List<Map<String, Object>> data = runSQL.executeMap(StringTools.format(querySql, qrtzTablePrefix, limit));

        disposeMap(data);

        long totalCount = ((BigInteger) runSQL.executeSQLSingleResult(StringTools.format(countSql, qrtzTablePrefix))).longValue();
        Pageable pageable = new PageRequest(page, rows);
        Page<Map<String, Object>> result = new PageImpl<>(data, pageable, totalCount);
        return Message.success("OK", result);
    }

    public void disposeMap(List<Map<String, Object>> data) throws IOException, ClassNotFoundException {
        for (Map<String, Object> item : data) {
            Object job_data = item.get("JOB_DATA");
            if (job_data != null) {
                ByteArrayInputStream byteInt = new ByteArrayInputStream((byte[]) job_data);
                ObjectInputStream objInt = new ObjectInputStream(byteInt);
                JobDataMap jobDataMap = (JobDataMap) objInt.readObject();
                item.put("JOB_DATA", jobDataMap);
            }
            if (item.get("NEXT_FIRE_TIME") != null) {
                Long nextTime = ((BigInteger) item.get("NEXT_FIRE_TIME")).longValue();
                item.put("NEXT_FIRE_TIME", TimeTools.getDateString(new Date(nextTime), TimeTools.Format.DATETIME));
            }

            if (item.get("PREV_FIRE_TIME") != null) {
                Long nextTime = ((BigInteger) item.get("PREV_FIRE_TIME")).longValue();
                item.put("PREV_FIRE_TIME", TimeTools.getDateString(new Date(nextTime), TimeTools.Format.DATETIME));
            }

            if (item.get("START_TIME") != null) {
                Long nextTime = ((BigInteger) item.get("START_TIME")).longValue();
                item.put("START_TIME", TimeTools.getDateString(new Date(nextTime), TimeTools.Format.DATETIME));
            }

            if (item.get("DESCRIPTION") != null) {
                Object description = item.get("DESCRIPTION");
                item.put("DESCRIPTION", URLDecoder.decode(description.toString(), "UTF-8"));
            }
        }
    }

    @ResponseBody
    @RequestMapping(value = "/saveOrUpdate", method = RequestMethod.POST, produces = {"application/json;charset=UTF-8"})
    public Message saveOrUpdate(@RequestBody JobDriver jobDriver) {
        try {
            setCharacterEncoding("UTF-8");
            System.out.println(jobDriver.getDescription());
            JOB.saveOrUpdate(jobDriver);
            return Message.success("OK");
        } catch (SchedulerException e) {
            log.error("Save Or Update Job Has Error:", e);
            e.printStackTrace();
            return Message.fail("ERROR:" + e.getMessage(), e);
        }
    }

    @ResponseBody
    @RequestMapping(value = "/delete", method = RequestMethod.DELETE)
    public Message delete(@RequestParam String name, @RequestParam(required = false) String group) {
        return Message.success("OK", JOB.delete(name, group));
    }

    @ResponseBody
    @RequestMapping(value = "/exists", method = RequestMethod.GET)
    public Message exists(@RequestParam String name, @RequestParam(required = false) String group) {
        return Message.success("OK", JOB.exists(name, group));
    }

    @ResponseBody
    @RequestMapping(value = "/pause", method = RequestMethod.GET)
    public Message pause(String name, @RequestParam(required = false) String group) {
        return Message.success("OK", JOB.pause(name, group));
    }

    @ResponseBody
    @RequestMapping(value = "/state", method = RequestMethod.GET)
    public Message state(@RequestParam String name, @RequestParam(required = false) String group) {
        return Message.success("OK", JOB.state(name, group));
    }

    @ResponseBody
    @RequestMapping(value = "/resume", method = RequestMethod.GET)
    public Message resume(@RequestParam String name, @RequestParam(required = false) String group) {
        return Message.success("OK", JOB.resume(name, group));
    }


}
